1
2
3
4 package joeq.Main;
5
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.LinkedList;
13 import java.util.Set;
14 import java.util.SortedSet;
15 import java.util.TreeSet;
16 import java.io.BufferedReader;
17 import java.io.DataOutputStream;
18 import java.io.File;
19 import java.io.FileOutputStream;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.io.RandomAccessFile;
23 import java.nio.channels.FileChannel;
24 import joeq.Allocator.CodeAllocator;
25 import joeq.Allocator.DefaultCodeAllocator;
26 import joeq.Allocator.HeapAllocator;
27 import joeq.Bootstrap.BootstrapCodeAddress;
28 import joeq.Bootstrap.BootstrapCodeAllocator;
29 import joeq.Bootstrap.BootstrapHeapAddress;
30 import joeq.Bootstrap.BootstrapRootSet;
31 import joeq.Bootstrap.SinglePassBootImage;
32 import joeq.Bootstrap.BootstrapCodeAddress.BootstrapCodeAddressFactory;
33 import joeq.Class.Delegates;
34 import joeq.Class.PrimordialClassLoader;
35 import joeq.Class.jq_Array;
36 import joeq.Class.jq_Class;
37 import joeq.Class.jq_Member;
38 import joeq.Class.jq_Method;
39 import joeq.Class.jq_Reference;
40 import joeq.Class.jq_StaticField;
41 import joeq.Class.jq_StaticMethod;
42 import joeq.Class.jq_Type;
43 import joeq.ClassLib.ClassLibInterface;
44 import joeq.Compiler.CompilationState;
45 import joeq.Compiler.BytecodeAnalysis.Trimmer;
46 import joeq.Compiler.CompilationState.BootstrapCompilation;
47 import joeq.Memory.CodeAddress;
48 import joeq.Memory.HeapAddress;
49 import joeq.Runtime.ObjectTraverser;
50 import joeq.Runtime.Reflection;
51 import joeq.Runtime.SystemInterface;
52 import joeq.Runtime.Unsafe;
53 import joeq.UTF.Utf8;
54 import jwutil.collections.LinearSet;
55 import jwutil.util.Assert;
56
57
58
59
60
61 public abstract class Bootstrapper {
62
63 private static SinglePassBootImage objmap;
64
65 public static void main(String[] args) throws IOException {
66
67 if (jq.RunningNative) {
68 System.err.println("Error: self-bootstrapping not supported (yet)");
69 System.exit(-1);
70 }
71
72 String imageName = "jq.obj";
73
74 String rootMethodClassName = "joeq.Main.JoeqVM";
75 String rootMethodName = "boot";
76 String classList = null;
77 String addToClassList = null;
78 boolean TrimAllTypes = false;
79 boolean DUMP_COFF = false;
80 boolean USE_BYTECODE_TRIMMER = true;
81
82
83 jq.on_vm_startup = new LinkedList();
84
85 CodeAddress.FACTORY = joeq.Bootstrap.BootstrapCodeAddress.FACTORY;
86 HeapAddress.FACTORY = joeq.Bootstrap.BootstrapHeapAddress.FACTORY;
87
88
89 jq.IsBootstrapping = true;
90 ClassLibInterface.useJoeqClasslib(true);
91
92 CodeAllocator.initializeCompiledMethodMap();
93 HeapAllocator.initializeDataSegment();
94
95 if (ClassLibInterface.DEFAULT.getClass().toString().indexOf("win32") != -1) {
96 DUMP_COFF = true;
97 } else {
98 DUMP_COFF = false;
99 }
100 String osarch = System.getProperty("os.arch");
101 if (osarch.equals("i386") || osarch.equals("x86")) {
102 try {
103 Class.forName("joeq.Scheduler.jq_x86RegisterState");
104 } catch (ClassNotFoundException e) {
105 System.err.println("Error: cannot load x86 module");
106 System.exit(-1);
107 }
108 String default_compiler_name = System.getProperty("joeq.compiler", "joeq.Compiler.Reference.x86.x86ReferenceCompiler$Factory");
109 Delegates.setDefaultCompiler(default_compiler_name);
110 } else {
111 System.err.println("Error: architecture "+osarch+" is not yet supported.");
112 System.exit(-1);
113 }
114
115 String classpath = System.getProperty("sun.boot.class.path")+
116 System.getProperty("path.separator")+
117 System.getProperty("java.class.path");
118
119 for (int i=0; i<args.length; ) {
120 int j = TraceFlags.setTraceFlag(args, i);
121 if (i != j) { i = j; continue; }
122 if (args[i].equals("-o")) {
123 imageName = args[++i];
124 ++i; continue;
125 }
126 if (args[i].equals("-r")) {
127 String s = args[++i];
128 int dotloc = s.lastIndexOf('.');
129 rootMethodName = s.substring(dotloc+1);
130 rootMethodClassName = s.substring(0, dotloc);
131 ++i; continue;
132 }
133 if (args[i].equals("-cp") || args[i].equals("-classpath")) {
134 classpath = args[++i];
135 ++i; continue;
136 }
137 if (args[i].equals("-cl") || args[i].equals("-classlist")) {
138 classList = args[++i];
139 ++i; continue;
140 }
141 if (args[i].equals("-a2cl") || args[i].equals("-addtoclasslist")) {
142 addToClassList = args[++i];
143 ++i; continue;
144 }
145 if (args[i].equals("-t")) {
146 TrimAllTypes = true;
147 ++i; continue;
148 }
149 if (args[i].equalsIgnoreCase("-borland")) {
150 SinglePassBootImage.USE_MICROSOFT_STYLE_MUNGE = false;
151 ++i; continue;
152 }
153 if (args[i].equalsIgnoreCase("-microsoft")) {
154 SinglePassBootImage.USE_MICROSOFT_STYLE_MUNGE = true;
155 ++i; continue;
156 }
157
158
159
160
161
162
163 err("unknown command line argument: "+args[i]);
164 }
165
166 rootMethodClassName = rootMethodClassName.replace('.','/');
167
168 System.out.println("Bootstrapping into "+imageName+", "+(DUMP_COFF?"COFF":"ELF")+" format, root method "+rootMethodClassName+"."+rootMethodName+(TrimAllTypes?", trimming all types.":"."));
169
170 for (Iterator it = PrimordialClassLoader.classpaths(classpath); it.hasNext(); ) {
171 String s = (String)it.next();
172 PrimordialClassLoader.loader.addToClasspath(s);
173 }
174
175
176
177
178
179
180
181 BootstrapCodeAllocator bca = BootstrapCodeAllocator.DEFAULT;
182 DefaultCodeAllocator.default_allocator = bca;
183 CodeAddress.FACTORY = BootstrapCodeAddress.FACTORY = new BootstrapCodeAddressFactory(bca);
184 bca.init();
185
186
187
188 ObjectTraverser obj_trav = ClassLibInterface.DEFAULT.getObjectTraverser();
189 Reflection.obj_trav = obj_trav;
190 obj_trav.initialize();
191
192 objmap = SinglePassBootImage.DEFAULT;
193
194
195 long starttime = System.currentTimeMillis();
196 jq_Class c;
197 c = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("L"+rootMethodClassName+";");
198 c.prepare();
199 long loadtime = System.currentTimeMillis() - starttime;
200
201 jq_StaticMethod rootm = null;
202 Utf8 rootm_name = Utf8.get(rootMethodName);
203 for(Iterator it = Arrays.asList(c.getDeclaredStaticMethods()).iterator();
204 it.hasNext(); ) {
205 jq_StaticMethod m = (jq_StaticMethod)it.next();
206 if (m.getName() == rootm_name) {
207 rootm = m;
208 break;
209 }
210 }
211 if (rootm == null)
212 err("root method not found: "+rootMethodClassName+"."+rootMethodName);
213
214 Set classset = new HashSet();
215 Set methodset;
216
217 starttime = System.currentTimeMillis();
218 if (addToClassList != null) {
219 BufferedReader dis = new BufferedReader(new FileReader(addToClassList));
220 for (;;) {
221 String classname = dis.readLine();
222 if (classname == null) break;
223 if (classname.charAt(0) == '#') continue;
224 jq_Type t = PrimordialClassLoader.loader.getOrCreateBSType(classname);
225 t.prepare();
226 classset.add(t);
227 }
228 }
229 if (classList != null) {
230 BufferedReader dis = new BufferedReader(new FileReader(classList));
231 for (;;) {
232 String classname = dis.readLine();
233 if (classname == null) break;
234 if (classname.equals("")) continue;
235 if (classname.charAt(0) == '#') continue;
236 if (classname.endsWith("*")) {
237 Assert._assert(classname.startsWith("L"));
238 Iterator i = PrimordialClassLoader.loader.listPackage(classname.substring(1, classname.length()-1));
239 while (i.hasNext()) {
240 String s = (String)i.next();
241 Assert._assert(s.endsWith(".class"));
242 s = "L"+s.substring(0, s.length()-6)+";";
243 jq_Class t = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType(s);
244 t.prepare();
245 classset.add(t);
246 for (;;) {
247 jq_Array q = t.getArrayTypeForElementType();
248 q.prepare();
249 classset.add(q);
250 t = t.getSuperclass();
251 if (t == null) break;
252 classset.add(t);
253 }
254 }
255 } else {
256 jq_Type t = PrimordialClassLoader.loader.getOrCreateBSType(classname);
257 t.prepare();
258 classset.add(t);
259 if (t instanceof jq_Class) {
260 jq_Class q = (jq_Class) t;
261 for (;;) {
262 t = q.getArrayTypeForElementType();
263 t.prepare();
264 classset.add(t);
265 q = q.getSuperclass();
266 if (q == null) break;
267 classset.add(q);
268 }
269 }
270 }
271 }
272 methodset = new HashSet();
273 Iterator i = classset.iterator();
274 while (i.hasNext()) {
275 jq_Type t = (jq_Type)i.next();
276 if (t.isClassType()) {
277 jq_Class cl = (jq_Class)t;
278 jq_Method[] ms = cl.getDeclaredStaticMethods();
279 for (int k=0; k<ms.length; ++k) {
280 methodset.add(ms[k]);
281 }
282 ms = cl.getDeclaredInstanceMethods();
283 for (int k=0; k<ms.length; ++k) {
284 methodset.add(ms[k]);
285 }
286 ms = cl.getVirtualMethods();
287 for (int k=0; k<ms.length; ++k) {
288 methodset.add(ms[k]);
289 }
290 }
291 }
292 } else {
293
294
295
296 if (USE_BYTECODE_TRIMMER) {
297 Trimmer trim = new Trimmer(rootm, classset, !TrimAllTypes);
298 trim.go();
299
300 BootstrapRootSet rs = trim.getRootSet();
301 System.out.println("Number of instantiated types: "+rs.getInstantiatedTypes().size());
302
303
304 System.out.println("Number of necessary methods: "+rs.getNecessaryMethods().size());
305
306
307 System.out.println("Number of necessary fields: "+rs.getNecessaryFields().size());
308
309
310
311 classset = rs.getNecessaryTypes();
312
313 System.out.println("Number of necessary classes: "+classset.size());
314
315
316 if (TrimAllTypes) {
317
318 Iterator it = classset.iterator();
319 while (it.hasNext()) {
320 jq_Type t = (jq_Type)it.next();
321 System.out.println("Trimming type: "+t.getName());
322 Assert._assert(t.isPrepared());
323 if (t.isClassType()) {
324 rs.trimClass((jq_Class)t);
325 }
326 }
327 System.out.println("Number of instance fields kept: "+jq_Class.NumOfIFieldsKept);
328 System.out.println("Number of static fields kept: "+jq_Class.NumOfSFieldsKept);
329 System.out.println("Number of instance methods kept: "+jq_Class.NumOfIMethodsKept);
330 System.out.println("Number of static methods kept: "+jq_Class.NumOfSMethodsKept);
331
332 System.out.println("Number of instance fields eliminated: "+jq_Class.NumOfIFieldsEliminated);
333 System.out.println("Number of static fields eliminated: "+jq_Class.NumOfSFieldsEliminated);
334 System.out.println("Number of instance methods eliminated: "+jq_Class.NumOfIMethodsEliminated);
335 System.out.println("Number of static methods eliminated: "+jq_Class.NumOfSMethodsEliminated);
336 }
337
338 methodset = rs.getNecessaryMethods();
339 } else {
340
341 BootstrapRootSet rs = null;
342 methodset = rs.getNecessaryMethods();
343 }
344 }
345 loadtime += System.currentTimeMillis() - starttime;
346 System.out.println("Load time: "+loadtime/1000f+"s");
347
348 if (classList == null) {
349 dumpClassSet(classset);
350 dumpMethodSet(methodset);
351 }
352
353
354 objmap.boot_types = classset;
355 BootstrapCompilation comp = (BootstrapCompilation) CompilationState.DEFAULT;
356 comp.setBootTypes(classset);
357
358 if (false) {
359 ArrayList class_list = new ArrayList(classset);
360 Collections.sort(class_list, new Comparator() {
361 public int compare(Object o1, Object o2) {
362 return ((jq_Type)o1).getDesc().toString().compareTo(((jq_Type)o2).getDesc().toString());
363 }
364 public boolean equals(Object o) { return this == o; }
365 });
366 System.out.println("Types:");
367 Set packages = new LinearSet();
368 Iterator it = class_list.iterator();
369 while (it.hasNext()) {
370 jq_Type t = (jq_Type)it.next();
371 String s = t.getDesc().toString();
372 System.out.println(s);
373 if (s.charAt(0) == 'L') {
374 int index = s.lastIndexOf('/');
375 if (index == -1) s = "";
376 else s = s.substring(1, index+1);
377 packages.add(s);
378 }
379 }
380 System.out.println("Packages:");
381 it = packages.iterator();
382 while (it.hasNext()) {
383 System.out.println("L"+it.next()+"*");
384 }
385 }
386
387
388 objmap.enableAllocations();
389
390 starttime = System.currentTimeMillis();
391
392
393
394 SystemInterface._class.sf_initialize();
395
396
397
398
399
400
401
402 Iterator it = classset.iterator();
403 while (it.hasNext()) {
404 jq_Type t = (jq_Type) it.next();
405 Assert._assert(t.isPrepared());
406 t.sf_initialize();
407 }
408 long sfinittime = System.currentTimeMillis() - starttime;
409 System.out.println("SF init time: "+sfinittime/1000f+"s");
410
411
412
413
414 starttime = System.currentTimeMillis();
415 it = methodset.iterator();
416 while (it.hasNext()) {
417 jq_Member m = (jq_Member)it.next();
418 if (m instanceof jq_Method) {
419 jq_Method m2 = ((jq_Method)m);
420 if (m2.getDeclaringClass() == Unsafe._class) continue;
421 if (m2.getDeclaringClass().isAddressType()) continue;
422 m2.compile();
423 }
424 }
425 long compiletime = System.currentTimeMillis() - starttime;
426 System.out.println("Compile time: "+compiletime/1000f+"s");
427
428
429
430
431 int numTypes = PrimordialClassLoader.loader.getNumTypes();
432 jq_Type[] types = PrimordialClassLoader.loader.getAllTypes();
433 for (int i = 0; i < numTypes; ++i) {
434 jq_Type t = types[i];
435 Reflection.getJDKType(t);
436 }
437
438
439
440 starttime = System.currentTimeMillis();
441 it = classset.iterator();
442 while (it.hasNext()) {
443 jq_Type t = (jq_Type)it.next();
444 Assert._assert(t.isSFInitialized());
445 if (t.isClassType()) {
446 jq_Class k = (jq_Class)t;
447 if (k.getSuperclass() != null &&
448 !classset.contains(k.getSuperclass())) {
449 Assert.UNREACHABLE(k.getSuperclass()+" (superclass of "+k+") is not in class set!");
450 }
451 jq_StaticField[] sfs = k.getDeclaredStaticFields();
452 for (int j=0; j<sfs.length; ++j) {
453 jq_StaticField sf = sfs[j];
454 if (sf.getType().isReferenceType() && !sf.getType().isAddressType()) {
455 Object val = Reflection.getstatic_A(sf);
456 objmap.getOrAllocateObject(val);
457 }
458 }
459 }
460 }
461
462
463
464 it = classset.iterator();
465 while (it.hasNext()) {
466 jq_Type t = (jq_Type)it.next();
467 Assert._assert(t.isSFInitialized());
468
469 if (t == Unsafe._class) continue;
470
471
472 t.compile();
473 t.cls_initialize();
474 objmap.initializeObject(t);
475 }
476
477
478 objmap.reinitializeObjects();
479
480
481
482 objmap.initializeObject(CodeAllocator.compiledMethods);
483
484
485
486
487 System.out.println("Number of classes seen = "+PrimordialClassLoader.loader.getNumTypes());
488 System.out.println("Number of classes in image = "+objmap.boot_types.size());
489
490
491 objmap.handleForwardReferences();
492
493
494 Utf8.NO_NEW = true;
495
496
497
498
499
500
501
502
503 it = classset.iterator();
504 while (it.hasNext()) {
505 jq_Type t = (jq_Type) it.next();
506 if (t.isReferenceType()) {
507 jq_Reference r = (jq_Reference) t;
508 if (r != Unsafe._class) {
509 objmap.initVTable(r);
510 }
511 if (r.isClassType()) {
512 jq_Class k = (jq_Class) t;
513 objmap.initStaticFields(k);
514 }
515 }
516 }
517
518 jq_Class jq_class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Main/jq;");
519 Assert._assert(classset.contains(jq_class));
520
521 jq_class.setStaticData(jq_class.getOrCreateStaticField("RunningNative","Z"), 1);
522
523 jq_class.setStaticData(jq_class.getOrCreateStaticField("IsBootstrapping","Z"), 0);
524 jq_Class utf8_class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/UTF/Utf8;");
525
526 utf8_class.setStaticData(utf8_class.getOrCreateStaticField("NO_NEW","Z"), 0);
527
528
529
530
531
532 HeapAddress addr = HeapAddress.addressOf(jq.on_vm_startup);
533 jq_StaticField _on_vm_startup = jq_class.getOrCreateStaticField("on_vm_startup", "Ljava/util/List;");
534 jq_class.setStaticData(_on_vm_startup, addr);
535 objmap.addDataReloc(_on_vm_startup.getAddress(), addr);
536
537
538 it = classset.iterator();
539 while (it.hasNext()) {
540 jq_Type t = (jq_Type) it.next();
541 if (t.isClassType()) {
542 jq_Class k = (jq_Class) t;
543 objmap.initStaticData(k);
544 objmap.addStaticFieldRelocs(k);
545 }
546 }
547
548
549 objmap.reinitializeObjects();
550
551
552 objmap.handleForwardReferences();
553
554 long traversaltime = System.currentTimeMillis() - starttime;
555
556
557 objmap.disableAllocations();
558
559 System.out.println("Scanned: "+objmap.numOfEntries()+" objects, memory used: "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+" ");
560 System.out.println("Scan time: "+traversaltime/1000f+"s");
561 System.out.println("Total number of Utf8 = "+(Utf8.size+1));
562 System.out.println("Code segment size = "+bca.size());
563 System.out.println("Data segment size = "+objmap.size());
564
565
566 objmap.initStaticField(CodeAllocator._lowAddress);
567 objmap.initStaticField(CodeAllocator._highAddress);
568 objmap.initStaticData(CodeAllocator._class);
569
570
571 HeapAllocator.data_segment_start = new BootstrapHeapAddress(-1);
572 HeapAllocator.data_segment_end = new BootstrapHeapAddress(objmap.size());
573 objmap.initStaticField(HeapAllocator._data_segment_start);
574 objmap.initStaticField(HeapAllocator._data_segment_end);
575 objmap.initStaticData(HeapAllocator._class);
576
577
578 File f = new File(imageName);
579 if (f.exists()) f.delete();
580 RandomAccessFile fos = new RandomAccessFile(imageName, "rw");
581 FileChannel fc = fos.getChannel();
582 starttime = System.currentTimeMillis();
583 try {
584 if (DUMP_COFF)
585 objmap.dumpCOFF(fc, rootm);
586 else
587 objmap.dumpELF(fc, rootm);
588 } finally {
589 fc.close();
590 fos.close();
591 }
592 long dumptime = System.currentTimeMillis() - starttime;
593 System.out.println("Dump time: "+dumptime/1000f+"s");
594
595 System.out.println(rootm.getDefaultCompiledVersion());
596
597
598
599
600
601 }
602
603 public static void dumpClassSet(Set s) throws IOException {
604 DataOutputStream dos = null;
605 try {
606 dos = new DataOutputStream(new FileOutputStream("classlist"));
607 SortedSet ss = new TreeSet();
608 for (Iterator i = s.iterator(); i.hasNext(); ) {
609 jq_Type t = (jq_Type) i.next();
610 ss.add(t.toString());
611 }
612 for (Iterator i = ss.iterator(); i.hasNext(); ) {
613 String t = (String) i.next();
614 dos.writeBytes(t + "\n");
615 }
616 } finally {
617 if (dos != null) dos.close();
618 }
619 }
620
621 public static void dumpMethodSet(Set s) throws IOException {
622 DataOutputStream dos = null;
623 try {
624 dos = new DataOutputStream(new FileOutputStream("methodlist"));
625 SortedSet ss = new TreeSet();
626 for (Iterator i = s.iterator(); i.hasNext(); ) {
627 jq_Method t = (jq_Method) i.next();
628 ss.add(t.toString());
629 }
630 for (Iterator i = ss.iterator(); i.hasNext(); ) {
631 String t = (String) i.next();
632 dos.writeBytes(t + "\n");
633 }
634 } finally {
635 if (dos != null) dos.close();
636 }
637 }
638
639 public static void err(String s) {
640 System.err.println(s);
641 System.exit(0);
642 }
643
644 }